package com.zxy.demo.task.impl;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.zxy.demo.task.TaskManager;
import com.zxy.demo.task.entity.BaseTask;

/**
 * 定时任务管理实现类
 * @author ZENG.XIAO.YAN
 * @version 1.0
 */

@Component
public class TaskManagerImpl implements TaskManager {
	@Autowired
	private Scheduler scheduler;
	/** trigger名字后缀 */
	private static final String TRIGGER_NAME_SUFFIX = "_trigger";
	private Logger log = LoggerFactory.getLogger(getClass());
	
	/**
	 * 添加定时任务
	 * @param jobName (这个jobName类似于id，需要保证不能重复)
	 * @param jobClassName
	 * @param cron
	 * @throws Exception 
	 */
	@Override
	public void addJob(String jobName, String jobClassName, String cron) throws Exception {
		Class<BaseTask> jobClass = this.getJobClass(jobClassName);
		if (!scheduler.isStarted()) {
			scheduler.start();
			log.info("---Quartz调度中心已手动启动---");
		}
		// 创建jobDetail
		// 这个jobClass必须实现了job接口
		JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName).build();
		// 创建表达式调度构建器
		CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(cron);
		// 创建Trigger对象
		CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName + TRIGGER_NAME_SUFFIX)
				.withSchedule(cronSchedule).build();
		// 添加到调度器中
		scheduler.scheduleJob(jobDetail, trigger);
		log.info("job {} add Success. cron --> {}" , jobName, cron);
	}
	
	
	/**
	 * 修改定时任务的时间
	 * @param jobName (这个jobName类似于id，需要保证不能重复)
	 * @param cron
	 * @throws Exception 
	 */
	@Override
	public void updateJobTime(String jobName, String cron) throws Exception {
			/**
			 * 方式一 ：调用 scheduler.rescheduleJob(TriggerKey triggerKey, Trigger newTrigger)
			 * 方式二 ：直接先删除任务，然后再新建
			 * <br/>这里采用了方式一
			 */
			// 生成triggerKey
			TriggerKey triggerKey = TriggerKey.triggerKey(jobName + TRIGGER_NAME_SUFFIX);
			// 从调度器中获取triggerKey对应trigger对象
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			if (null == trigger) {
				// 如果trigger 未找到，那么该任务不存在。
				return ;
			}
			// 创建新的表达式调度构建器
			// 注意：调用withMisfireHandlingInstructionDoNothing()——等待下次Cron触发频率到达时刻开始按照Cron频率依次执行，否则会立即执行
			CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing();
			// 修改trigger，重新创建一个
			trigger = TriggerBuilder.newTrigger().withIdentity(jobName + TRIGGER_NAME_SUFFIX).withSchedule(cronSchedule)
					.build();
			// 调度器中更新任务触发器
			scheduler.rescheduleJob(triggerKey, trigger);
			log.info("job {} updateTime Success cron --> {} ", jobName, cron);
	}
	
	
	/**
	 * 暂停指定定时任务
	 * @param jobName (这个jobName类似于id，需要保证不能重复)
	 * @throws Exception 
	 */
	public void pauseJob(String jobName) throws Exception {
		// 生成jobKey
		JobKey jobKey = JobKey.jobKey(jobName);
		// 调度器中停止jobKey对应的job
		scheduler.pauseJob(jobKey);;
		log.info("job {} pause Success", jobName);
	}
	
	
	/**
	 * 重启指定定时任务
	 * @param jobName
	 * @throws Exception 
	 */
	public void resumeJob(String jobName) throws Exception {
		// 生成jobKey
		JobKey jobKey = JobKey.jobKey(jobName);
		// 调度器中重启对应的job
		scheduler.resumeJob(jobKey);;
		log.info("job {} resume Success", jobName);
	}
	
	
	/**
	 * 删除指定定时任务
	 * @param jobName
	 * @throws Exception 
	 */
	@Override
	public void deleteJob(String jobName) throws Exception {
		TriggerKey triggerKey = TriggerKey.triggerKey(jobName + TRIGGER_NAME_SUFFIX);
		JobKey jobKey = JobKey.jobKey(jobName);
		// 停止触发器
		scheduler.pauseTrigger(triggerKey);
		// 移除触发器
		scheduler.unscheduleJob(triggerKey);
		// 删除任务
		scheduler.deleteJob(jobKey);
		log.info("job {} delete Success", jobName);
	}
	
	
	/**
	 * 通过 className获取字节码对象
	 * @param jobClassName
	 * @return
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	private Class<BaseTask> getJobClass(String jobClassName) throws ClassNotFoundException {
		Class<BaseTask> clazz = (Class<BaseTask>) Class.forName(jobClassName);
		return clazz;
	}
	
}
